linux Loadavg和CPU利用率是如何算出来的 您所在的位置:网站首页 fire loading怎么算 linux Loadavg和CPU利用率是如何算出来的

linux Loadavg和CPU利用率是如何算出来的

2024-03-06 15:41| 来源: 网络整理| 查看: 265

相信很多人都对Linux中top命令里“load average”这一栏困惑过,到底什么是Load,Load代表了什么含义,Load高会有什么后果?“%CPU”这一栏为什么会超过100%,它是如何计算的? 带着这些问题,我们通过一些测试,来探索下其中的不解之处。

首先,我们通过实验来大概确定其计算方式: 测试服务器:4核Xeon处理器 测试软件:MySQL 5.1.40 服务器上除了MySQL没有运行其他任何非系统自带软件。因为MySQL只能单线程运行单条SQL,所以可以很好的通过增加查询并发来控制使用的CPU核数。

空载时,top的信息为:

top – 14:51:47 up 35 days, 4:43, 1 user, load average: 0.00, 0.00, 0.00 Tasks: 76 total, 1 running, 75 sleeping, 0 stopped, 0 zombie Cpu(s): 0.0%us, 0.0%sy, 0.0%ni, 99.5%id, 0.1%wa, 0.2%hi, 0.2%si, 0.0%st

在数据库中启动一个大查询:

top – 15:28:09 up 35 days, 5:19, 3 users, load average: 0.99, 0.92, 0.67 Tasks: 80 total, 1 running, 79 sleeping, 0 stopped, 0 zombie Cpu0 : 0.0%us, 0.0%sy, 0.0%ni, 96.3%id, 0.0%wa, 1.3%hi, 2.3%si, 0.0%st Cpu1 : 0.0%us, 0.0%sy, 0.0%ni,100.0%id, 0.0%wa, 0.0%hi, 0.0%si, 0.0%st Cpu2 : 98.7%us, 1.3%sy, 0.0%ni, 0.0%id, 0.0%wa, 0.0%hi, 0.0%si, 0.0%st Cpu3 : 0.0%us, 0.0%sy, 0.0%ni,100.0%id, 0.0%wa, 0.0%hi, 0.0%si, 0.0%st

同时可以看到%CPU也是在100%

PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND 877 mysql 15 0 308m 137m 4644 S 99.9 6.8 15:13.28 mysqld

然后开启第二个大查询,不久就可以看到top信息的变化,Load到了2:

top – 15:36:44 up 35 days, 5:28, 3 users, load average: 1.99, 1.62, 1.08 Tasks: 80 total, 1 running, 79 sleeping, 0 stopped, 0 zombie Cpu0 : 0.0%us, 0.0%sy, 0.0%ni, 97.7%id, 0.0%wa, 1.0%hi, 1.3%si, 0.0%st Cpu1 : 99.0%us, 1.0%sy, 0.0%ni, 0.0%id, 0.0%wa, 0.0%hi, 0.0%si, 0.0%st Cpu2 : 0.0%us, 0.0%sy, 0.0%ni,100.0%id, 0.0%wa, 0.0%hi, 0.0%si, 0.0%st Cpu3 : 99.0%us, 1.0%sy, 0.0%ni, 0.0%id, 0.0%wa, 0.0%hi, 0.0%si, 0.0%st

也可以观察到%CPU增加到了200%:

PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND 877 mysql 15 0 312m 141m 4644 S 199.8 7.0 22:31.27 mysqld

由此可以简单的做出如下临时结论: 1. %CPU是由每个核的CPU占用律之和算出来的。 2. load跟执行的任务数有关 不过要想准确的知道其含义,还是必须从源码入手。

CPU利用率的计算方法

下载busybox的源码,在procps目录下有top.c的源码,查看第293行附近(1.17.1版),可以看到

if (prev_hist_count) do { if (prev_hist[i].pid == pid) { cur-;pcpu = cur-;ticks - prev_hist[i].ticks; total_pcpu += cur-;pcpu; break; } i = (i+1) % prev_hist_count; /* hist_iterations++; */ } while (i != last_i);

这就是计算%CPU的代码,很明显total_pcpu就是累加了每个线程对每个核的使用率,所以%CPU的最大值就是核数*100%。

而CPU利用率又是怎么计算的呢,跟踪代码可以发现,是从系统的/proc/stat这里读取的,这个文件的格式可以参考:http://www.linuxhowtos.org/System/procstat.htm,下面是我笔记本上读出来的内容。

plx@plinux-Laptop:~/busybox-1.17.1$ cat /proc/stat cpu 520529 3525 658608 3500749 210662 6650 29698 0 0 cpu0 249045 1936 466387 1624486 136381 308 17051 0 0 cpu1 271483 1588 192221 1876263 74281 6342 12646 0 0 intr 84067574 42497789 41743 0 0 0 0 0 0 1 57928 0 0 7175 0 0 0 477092 24693 0 5 0 183 0 20 0 0 0 12455 821851 745906 10192555 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ctxt 142313984 btime 1281403521 processes 6707 procs_running 2 procs_blocked 0 softirq 56932805 0 20168080 9440286 238191 821787 0 10621375 4052209 13257 11577620

cpuN的含义从左到右分别是:user、system、nice、idle、iowait、irq、softirq,具体含义可以看文档。 在下面几行的含义是: “intr”这行给出中断的信息,第一个为自系统启动以来,发生的所有的中断的次数;然后每个数对应一个特定的中断自系统启动以来所发生的次数。 “ctxt”给出了自系统启动以来CPU发生的上下文交换的次数。 “btime”给出了从系统启动到现在为止的时间,单位为秒。 “processes (total_forks) 自系统启动以来所创建的任务的个数目。 “procs_running”:当前运行队列的任务的数目。 “procs_blocked”:当前被阻塞的任务的数目。 那么CPU利用率可以使用以下方法,先取两个采样点,然后计算其差值:

cpu usage=(idle2-idle1)/(cpu2-cpu1)*100 cpu usage=[(user_2 +sys_2+nice_2) - (user_1 + sys_1+nice_1)]/(total_2 - total_1)*100;

这是一段Bash代码采集利用率的,摘自网络:

#!/bin/sh ##echo user nice system idle iowait irq softirq CPULOG_1=$(cat /proc/stat | grep 'cpu ' | awk '{print $2" "$3" "$4" "$5" "$6" "$7" "$8}') SYS_IDLE_1=$(echo $CPULOG_1 | awk '{print $4}') Total_1=$(echo $CPULOG_1 | awk '{print $1+$2+$3+$4+$5+$6+$7}')   sleep 5   CPULOG_2=$(cat /proc/stat | grep 'cpu ' | awk '{print $2" "$3" "$4" "$5" "$6" "$7" "$8}') SYS_IDLE_2=$(echo $CPULOG_2 | awk '{print $4}') Total_2=$(echo $CPULOG_2 | awk '{print $1+$2+$3+$4+$5+$6+$7}')   SYS_IDLE=`expr $SYS_IDLE_2 - $SYS_IDLE_1`   Total=`expr $Total_2 - $Total_1` SYS_USAGE=`expr $SYS_IDLE/$Total*100 |bc -l`   SYS_Rate=`expr 100-$SYS_USAGE |bc -l`   Disp_SYS_Rate=`expr "scale=3; $SYS_Rate/1" |bc` echo $Disp_SYS_Rate%

还有一段Perl的代码,也是摘自网络:

#!/usr/bin/perl use warnings;   $SLEEPTIME=5;   if (-e "/tmp/stat") { unlink "/tmp/stat"; } open (JIFF_TMP, ";;/tmp/stat") || die "Can't open /proc/stat file!\n"; open (JIFF, "/proc/stat") || die "Can't open /proc/stat file!\n"; @jiff_0=; print JIFF_TMP $jiff_0[0] ; close (JIFF);   sleep $SLEEPTIME;   open (JIFF, "/proc/stat") || die "Can't open /proc/stat file!\n"; @jiff_1=; print JIFF_TMP $jiff_1[0]; close (JIFF); close (JIFF_TMP);   @USER=`awk '{print \$2}' "/tmp/stat"`; @NICE=`awk '{print \$3}' "/tmp/stat"`; @SYSTEM=`awk '{print \$4}' "/tmp/stat"`; @IDLE=`awk '{print \$5}' "/tmp/stat"`; @IOWAIT=`awk '{print \$6}' "/tmp/stat"`; @IRQ=`awk '{print \$7}' "/tmp/stat"`; @SOFTIRQ=`awk '{print \$8}' "/tmp/stat"`;   $JIFF_0=$USER[0]+$NICE[0]+$SYSTEM[0]+$IDLE[0]+$IOWAIT[0]+$IRQ[0]+$SOFTIRQ[0]; $JIFF_1=$USER[1]+$NICE[1]+$SYSTEM[1]+$IDLE[1]+$IOWAIT[1]+$IRQ[1]+$SOFTIRQ[1]; $SYS_IDLE=($IDLE[0]-$IDLE[1]) / ($JIFF_0-$JIFF_1) * 100; $SYS_USAGE=100 - $SYS_IDLE;   printf ("The CPU usage is %1.2f%%\n",$SYS_USAGE);

Load的计算方法

跟踪busybox的代码可以知道,load是从/proc/loadavg中读取的。 我本机的一次抓取内容如下:

plx@plinux-Laptop:~/busybox-1.17.1$ cat /proc/loadavg 0.64 0.81 0.86 3/364 6930

每个值的含义依次为: lavg_1 (0.64) 1-分钟平均负载 lavg_5 (0.81) 5-分钟平均负载 lavg_15(0.86) 15-分钟平均负载 nr_running (3) 在采样时刻,运行队列的任务的数目,与/proc/stat的procs_running表示相同意思 nr_threads (364) 在采样时刻,系统中活跃的任务的个数(不包括运行已经结束的任务) last_pid(6930) 最大的pid值,包括轻量级进程,即线程。 假设当前有两个CPU,则每个CPU的当前任务数为0.64/2=0.32

我们可以在Linux内核中找到loadavg文件的源码:

tatic int loadavg_read_proc(char *page, char **start, off_t off, int count, int *eof, void *data) { int a, b, c; int len; #   a = avenrun[0] + (FIXED_1/200); b = avenrun[1] + (FIXED_1/200); c = avenrun[2] + (FIXED_1/200); len = sprintf(page,"%d.%02d %d.%02d %d.%02d %ld/%d %d\n", LOAD_INT(a), LOAD_FRAC(a), LOAD_INT(b), LOAD_FRAC(b), LOAD_INT(c), LOAD_FRAC(c), nr_running(), nr_threads, last_pid); return proc_calc_metrics(page, start, off, count, eof, len); }

以及计算load的代码:

#define FSHIFT 11 /* nr of bits of precision */ #define FIXED_1 (1= FSHIFT;   unsigned long avenrun[3];   EXPORT_SYMBOL(avenrun);   /* * calc_load - given tick count, update the avenrun load estimates. * This is called while holding a write_lock on xtime_lock. */ static inline void calc_load(unsigned long ticks) { unsigned long active_tasks; /* fixed-point */ static int count = LOAD_FREQ; count -= ticks; if (count


【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有